home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 49
/
Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso
/
-in_the_mag-
/
news
/
csppc233fix
/
csppc233fix_ppc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-12-14
|
9KB
|
285 lines
/*
* LRBug.c
*
* Try to work around what seems to be a hardware bug of CyberstormPPC
* 604e/233 cards.
*
* Written by Emmanuel Lesueur lesueur@club-internet.fr
*
* This code is in the public domain. You can do whatever you want with it.
*
*
* CLI Usage:
* LRBug NOREQ/S,QUIET/S,NOWAIT/S
*
* NOREQ: don't ask before attempting to restart a task.
* QUIET: don't write messages with kprinf() when restarting a task.
* NOWAIT: don't install a handler, just restart crashed tasks and quit.
*
* WB Usage:
* Tooltypes NOREQ, QUIET, and NOWAIT, with the same meaning.
*
* To remove the handler, send a CTRL-C.
*
*
* Object:
* Install an exception handler to catch exceptions caused by a
* corrupted LR (bit 0 or 2 incorrectly set). When one is caught,
* clear the bad bit and restart the task.
*
* Issue:
* Unfortunately, I don't know of any way to fall back to the default
* exception handler for exceptions that are not of the "bad LR" type. So
* in that case, I just display a small message via kprintf() and let the
* user run PPCShowTrap to get the full register/MMU/stack dump.
*
*
* To compile with SAS/C 6.58:
* sc resetopts cpu=68040 params=registers nostackcheck optimize
* optimizesize link stripdebug nostartup lib lib:debug.lib LRBug.c
*
* To compile with gcc:
* gcc -o LRBug -O2 -m68040 -nostdlib LRBug.c -ldebug
*
* To compile with vbcc:
* vc -o LRBug -O2 -cpu=68040 -nostdlib LRBug.c -lamiga -lppc -ldebug
*
* Others:
* I don't know, but: SHOULD BE LINKED WITH NO STARTUP !
*/
#include <stdio.h>
#include <string.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <workbench/startup.h>
#include <powerup/ppclib/ppc.h>
#include <powerup/ppclib/tasks.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/icon.h>
#include <powerup/proto/ppc.h>
#ifdef __SASC
# define SAVEDS __saveds
# define ASM __asm
# define REG(x,y) register __##x y
#elif defined(__GNUC__)
# define SAVEDS
# define ASM
# define REG(x,y) y __asm__(#x)
#elif defined(_DCC)
# define SAVEDS __geta4
# define ASM
# define REG(x,y) __##x y
#elif defined(__STORM__)
# define SAVEDS __saveds
# define ASM
# define REG(x,y) register __##x y
#elif defined(__VBCC__)
# define SAVEDS
# define ASM
# define REG(x,y) __reg(#x) y
#else
# error add #defines for your compiler...
#endif
typedef BOOL ASM hook_func(REG(a0,struct Hook* h),
REG(a2,void* t),
REG(a1,struct ExceptionMsg* em));
static void* maintask;
static struct Hook* oldhook;
static BOOL noreq,quiet;
struct Library* PPCLibBase;
struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase;
struct DosLibrary *DOSBase;
struct Library *IconBase;
void kprintf(const char*,...);
void install_handler(void);
void scan_tasks_list(void);
/*
* Program entry point. No startup code needed.
*/
int SAVEDS start(void) {
struct Process *proc;
struct WBStartup *wbmsg=NULL;
int ret=RETURN_FAIL;
SysBase=*(struct ExecBase**)4;
proc=(struct Process*)FindTask(NULL);
if(!proc->pr_CLI) {
WaitPort(&proc->pr_MsgPort);
wbmsg=(struct WBStartup*)GetMsg(&proc->pr_MsgPort);
}
if((DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",36)) &&
(IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39))) {
if(PPCLibBase=OpenLibrary("ppc.library",46)) {
maintask=FindTask(NULL);
if(proc->pr_CLI) {
struct RDArgs *rda;
LONG args[3]={0,0,0};
if(rda=ReadArgs("NOREQ/S,QUIET/S,NOWAIT/S",args,NULL)) {
ret=RETURN_OK;
noreq=args[0];
quiet=args[1];
if(args[2])
scan_tasks_list();
else
install_handler();
FreeArgs(rda);
} else
PrintFault(IoErr(),"Error: ");
} else {
BPTR olddir=CurrentDir(wbmsg->sm_ArgList[0].wa_Lock);
struct DiskObject *dob;
if(IconBase=OpenLibrary("icon.library",36)) {
if(dob=GetDiskObjectNew(wbmsg->sm_ArgList[0].wa_Name)) {
ret=RETURN_OK;
noreq=dob->do_ToolTypes &&
FindToolType((UBYTE **)dob->do_ToolTypes,
(UBYTE *)"NOREQ");
quiet=dob->do_ToolTypes &&
FindToolType((UBYTE **)dob->do_ToolTypes,
(UBYTE *)"QUIET");
if(dob->do_ToolTypes &&
FindToolType((UBYTE **)dob->do_ToolTypes,
(UBYTE *)"NOWAIT"))
scan_tasks_list();
else
install_handler();
FreeDiskObject(dob);
}
CloseLibrary(IconBase);
}
CurrentDir(olddir);
}
CloseLibrary((struct Library*)PPCLibBase);
} else
Printf("Can't open ppc.library V46\n");
}
CloseLibrary((struct Library*)IntuitionBase);
CloseLibrary((struct Library*)DOSBase);
if(wbmsg) {
Forbid();
ReplyMsg(&wbmsg->sm_Message);
}
return ret;
}
/*
* Exception hook:
* - If the exception looks like one caused by the LR bug (i.e.
* PC==LR and bit 0 or 2 of LR set), signal our main task.
* - otherwise, if there was an old exception hook, call it.
* - otherwise, if the exception is a real one (not a kernel message),
* kprintf a message to signal it to the user. I'd like to
* fall back to the default handling (showing regs, stack, ...),
* but I don't think it's possible. One can always use
* PPCShowTrap to display those informations, anyway.
*/
BOOL SAVEDS ASM exception_func(REG(a0,struct Hook* h),
REG(a2,void* task),
REG(a1,struct ExceptionMsg* em)) {
if(em->Type==EXCEPTION_DATAACCESS &&
em->SRR0==em->LR &&
((em->LR&0xf0000000)==0x20000000 ||
(em->LR&0xf0000000)==0x80000000)) {
/*
* This hook is called with task==NULL, so we don't know
* which task to restart. To work around that problem,
* the main task will scan the tasks list and retrieve
* it by checking LR's. No need to save the exception message.
*/
Signal(maintask,SIGBREAKF_CTRL_F);
return TRUE;
} else if(oldhook) {
return ((hook_func*)oldhook->h_Entry)(oldhook,task,em);
} else {
if(!(em->Type&EXCEPTION_MSG))
kprintf("Exception %lx. Use PPCShowTrap for details.\n",em->Type);
return FALSE;
}
}
static struct Hook hook={{NULL,NULL},(ULONG (*)())exception_func};
/*
* Restart a task.
*/
void restart(void* task,ULONG lr) {
PPCSetTaskAttrsTags(task,
PPCTASKINFOTAG_PC,&lr,
PPCTASKINFOTAG_LR,&lr,
TAG_END);
PPCStartTaskTags(task,PPCTASKSTARTTAG_RUN,TRUE,TAG_END);
}
/*
* Task list scanning hook. Look for tasks that have bad PC/LR,
* and restart them.
*/
void SAVEDS ASM scantasks_func(REG(a2,void* task)) {
ULONG pc,lr,state;
state=PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_STATE,NULL,TAG_END);
PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_PC,&pc,TAG_END);
PPCGetTaskAttrsTags(task,PPCTASKINFOTAG_LR,&lr,TAG_END);
if(state==TS_WAIT && pc==lr &&
((lr&0xf0000000)==0x20000000 || (lr&0xf0000000)==0x80000000)) {
static struct EasyStruct es={
sizeof(struct EasyStruct),0,"LRBug Exception Handler",
"LR bug caught in task\n\"%s\"",
"Continue|Suspend",
};
const char* name=(const char*)PPCGetTaskAttrsTags(task,
PPCTASKINFOTAG_NAME,NULL,
TAG_END);
if(!quiet)
kprintf("LR bug caught in task \"%s\" (%lx).\n",name,task);
lr&=~0xf0000000;
if(noreq)
restart(task,lr);
else {
if(EasyRequest(NULL,&es,NULL,name)==1)
restart(task,lr);
}
}
}
void scan_tasks_list(void) {
static struct Hook scantasks_hook={{NULL,NULL},(ULONG (*)())scantasks_func};
PPCGetTaskAttrsTags(NULL,
PPCTASKINFOTAG_HOOK,&scantasks_hook,
PPCTASKINFOTAG_ALLTASK,TRUE,
TAG_END);
}
/*
* Install the exception handler and wait for events.
*/
void install_handler(void) {
oldhook=(struct Hook *)PPCGetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,NULL,TAG_END);
PPCSetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,&hook,TAG_END);
while(!(Wait(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_F)&SIGBREAKF_CTRL_C))
scan_tasks_list();
PPCSetAttrsTags(PPCINFOTAG_EXCEPTIONHOOK,oldhook,TAG_END);
}